#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include "esp_system.h"
#include "esp_log.h"
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "esp_http_client.h"
#include "cJSON.h"
#include "i2s_recorder.h"
#include "player.h"
#include "led/led_manager.h"

/**
 * I2S引脚定义
 */
#define I2S_WS_IO           42
#define I2S_SCK_IO          41
#define I2S_SD_IO           2

/**
 * I2S配置参数
 */
#define SAMPLE_RATE         16000
#define I2S_NUM             I2S_NUM_1
#define I2S_BUF_SIZE        1024

// GPIO配置
#define GPIO_RECORD_BUTTON     45
#define MAX_HTTP_OUTPUT_BUFFER 512
//LED
#define LED_GPIO_PIN           47

// 静音阈值，可根据实际情况调整
#define NO_SOUND_THRESHOLD 1000
// 3秒静音持续时间
#define SILENCE_DURATION_MS 2000

static const char *TAG = "I2S_RECORDER";
static volatile bool recording = false;
static volatile bool button_pressed = false;
static char *i2s_read_buff = NULL;
static size_t total_bytes_read = 0;
static char *recorded_data = NULL;

TaskHandle_t silenceDetectionTaskHandle;
LEDManager record_led_manager;

/**
 * WAV 文件头
 */
typedef struct {
    char riff_header[4];         // "RIFF"
    uint32_t wav_size;           // 文件大小 - 8
    char wave_header[4];         // "WAVE"
    char fmt_header[4];          // "fmt "
    uint32_t fmt_chunk_size;     // 16 for PCM
    uint16_t audio_format;       // 1 for PCM
    uint16_t num_channels;       // 1 for mono
    uint32_t sample_rate;        // 16000
    uint32_t byte_rate;          // sample_rate * num_channels * bits_per_sample / 8
    uint16_t sample_alignment;   // num_channels * bits_per_sample / 8
    uint16_t bits_per_sample;    // 16 bits
    char data_header[4];         // "data"
    uint32_t data_bytes;         // Number of bytes in data
} wav_header_t;

/**
 * HTTP事件处理函数
 */
esp_err_t _http_event_handler(esp_http_client_event_t *evt) {
    // 用于存储来自事件处理程序的http请求响应的缓冲区
    static char *output_buffer;  
    // 存储读取的字节数
    static int output_len;       
    switch(evt->event_id) {
        case HTTP_EVENT_ERROR:
            ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
            break;
        case HTTP_EVENT_ON_CONNECTED:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
            break;
        case HTTP_EVENT_HEADER_SENT:
            ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
            break;
        case HTTP_EVENT_ON_HEADER:
            ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
            break;
        case HTTP_EVENT_ON_DATA:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
            if (!esp_http_client_is_chunked_response(evt->client)) {
                // 如果响应没有分块，则将数据复制到缓冲区
                if (evt->user_data) {
                    memcpy(evt->user_data + output_len, evt->data, evt->data_len);
                } else {
                    if (output_buffer == NULL) {
                        output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
                        output_len = 0;
                        if (output_buffer == NULL) {
                            ESP_LOGE(TAG, "无法为输出缓冲区分配内存");
                            return ESP_FAIL;
                        }
                    }
                    memcpy(output_buffer + output_len, evt->data, evt->data_len);
                }
                output_len += evt->data_len;
            }
            break;
        case HTTP_EVENT_ON_FINISH:
            ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
            if (output_buffer != NULL) {
                // 输出响应
                // null-终止缓冲区
                output_buffer[output_len] = 0;  
                ESP_LOGI(TAG, "Response: %s", output_buffer);

                // 解析json
                cJSON *json = cJSON_Parse(output_buffer);
                if (json == NULL) {
                    ESP_LOGE(TAG, "JSON解析错误");
                } else {
                    cJSON *data = cJSON_GetObjectItem(json, "data");
                    cJSON *status = cJSON_GetObjectItem(json, "status");
                    cJSON *message = cJSON_GetObjectItem(json, "message");
                    cJSON *serviceTime = cJSON_GetObjectItem(json, "serviceTime");

                    if (cJSON_IsNumber(status) && status->valueint == 200) {
                        // 确保字符串有效
                        if (data != NULL && cJSON_IsString(data)) {
                            const char *url = data->valuestring;
                            // 复制URL字符串
                            char *url_copy = strdup(url);
                            if (url_copy != NULL) {
                                ESP_LOGI(TAG, "解析后的URL：%s", url_copy);
                                xTaskCreate(audio_task, "AUDIO_TASK", 8192, (void *)url_copy, 5, NULL);
                                led_manager_set_level(&record_led_manager, 0);
                            } else {
                                ESP_LOGE(TAG, "URL 复制失败");
                            }
                        } else {
                            ESP_LOGE(TAG, "数据项无效");
                        }
                    } else {
                        ESP_LOGE(TAG, "返回值错误：%s", message->valuestring);
                    }

                    // if (cJSON_IsNumber(status) && status->valueint == 200) {
                    //     const char *url = data->valuestring;
                    //     ESP_LOGI(TAG, "解析后的URL：%s", url);
                    //     xTaskCreate(audio_task, "AUDIO_TASK", 8192, (void *)url, 5, NULL);

                    // } else {
                    //     ESP_LOGE(TAG, "返回值错误：%s", message->valuestring);
                    // }
                    cJSON_Delete(json);
                }

                free(output_buffer);
                output_buffer = NULL;
            }
            output_len = 0;
            break;
        case HTTP_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
            // int mbedtls_err = 0;
            // esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL);
            // if (err != 0) {
            //     ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
            //     ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
            // }
            if (output_buffer != NULL) {
                free(output_buffer);
                output_buffer = NULL;
            }
            output_len = 0;
            break;
        case HTTP_EVENT_REDIRECT:
            ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
            break;
    }
    return ESP_OK;
}

/**
 * 注意：中断方法中不能放耗时较长或阻塞的程序
 */
void IRAM_ATTR gpio_isr_handler(void* arg) {
    int level = gpio_get_level(GPIO_RECORD_BUTTON);
    // 高电平表示按下
    button_pressed = (level == 1); 
}

void i2s_recorder_init(void) {
    // 初始化LED
    led_manager_init(&record_led_manager, LED_GPIO_PIN);

    // 配置i2s 驱动
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = I2S_BITS_PER_CHAN_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .dma_buf_count = 4,
        .dma_buf_len = I2S_BUF_SIZE,
        .use_apll = false,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1
    };

    // 配置I2S引脚
    i2s_pin_config_t pin_config = {
        .bck_io_num = I2S_SCK_IO,
        .ws_io_num = I2S_WS_IO,
        .data_out_num = I2S_PIN_NO_CHANGE,
        .data_in_num = I2S_SD_IO
    };

    // 安装并启动I2S引脚
    ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL));
    ESP_ERROR_CHECK(i2s_set_pin(I2S_NUM, &pin_config));

    // 设置I2S时钟
    ESP_ERROR_CHECK(i2s_set_clk(I2S_NUM, SAMPLE_RATE, I2S_BITS_PER_CHAN_16BIT, I2S_CHANNEL_MONO));

    // 配置GPIO
    gpio_config_t io_config = {
        // 任何边沿触发中断
        .intr_type = GPIO_INTR_ANYEDGE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ULL << GPIO_RECORD_BUTTON),
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        // 启用上拉
        .pull_up_en = GPIO_PULLUP_ENABLE 
    };
    gpio_config(&io_config);

    // 安装 GPIO ISR 服务
    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1));
    ESP_ERROR_CHECK(gpio_isr_handler_add(GPIO_RECORD_BUTTON, gpio_isr_handler, (void*) GPIO_RECORD_BUTTON));

    // 分配缓冲区以存储I2S数据
    i2s_read_buff = (char*)calloc(I2S_BUF_SIZE, sizeof(char));
    if (i2s_read_buff == NULL) {
        ESP_LOGE(TAG, "内存分配失败");
    }

    ESP_LOGI(TAG, "I2S 录音初始化完成");
}

void i2s_recorder_start(void) {
    if (!recording) {
        recording = true;
        // 重置总读取字节数
        total_bytes_read = 0; 
        // 释放之前的录音数据
        free(recorded_data);
        // 分配1M的缓存区
        recorded_data = (char *)malloc(1024 * 1024);
        if (recorded_data == NULL) {
            ESP_LOGE(TAG, "内存分配失败");
            recording = false;
        } else {
            ESP_LOGI(TAG, "录音开始");
        }
    }
}

void add_wav_header(char *data, size_t data_len, char *wav_data, size_t *wav_data_len) {
    wav_header_t header;
    memcpy(header.riff_header, "RIFF", 4);
    header.wav_size = 36 + data_len;
    memcpy(header.wave_header, "WAVE", 4);
    memcpy(header.fmt_header, "fmt ", 4);
    header.fmt_chunk_size = 16;
    header.audio_format = 1;
    header.num_channels = 1;
    header.sample_rate = SAMPLE_RATE;
    header.byte_rate = SAMPLE_RATE * 2;
    header.sample_alignment = 2;
    header.bits_per_sample = 16;
    memcpy(header.data_header, "data", 4);
    header.data_bytes = data_len;

    // 复制 WAV 头和数据
    memcpy(wav_data, &header, sizeof(header));
    memcpy(wav_data + sizeof(header), data, data_len);
    *wav_data_len = sizeof(header) + data_len;
}

void i2s_recorder_stop(void) {
    if (recording) {
        recording = false;
        ESP_LOGI(TAG, "录音停止。读取的总字节数：%d", total_bytes_read);
        // 发送数据到服务器
        if (total_bytes_read > 0) {
            // WAV 头大小为 44 字节
            char *wav_data = (char *) malloc(total_bytes_read + 44); 
            size_t wav_data_len;
            add_wav_header(recorded_data, total_bytes_read, wav_data, &wav_data_len);

            // 配置http请求
            // 使用大小（MAX_HTTP_OUTPUT_BUFFER+1）声明local_response_buffer，以防止超出绑定访问
            // 它被strlen（）等函数使用。缓冲区只能使用到最大MAX_HTTP_OUTPUT_BUFFER
            // char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER + 1] = {0};
            esp_http_client_config_t config = {
                .host = "192.168.2.49",                 // 主机名或 IP 地址
                .port = 8080,                           // 请求路径
                .path = "/api/audio/upload",            // 查询参数
                .event_handler = _http_event_handler,   // 事件处理函数
                // .user_data = local_response_buffer,     // 用户数据缓冲区，需要在这里输出请求后结果则设置
                .disable_auto_redirect = true,          // 禁用自动重定向
                .timeout_ms = 10000                     // 设置超时时间为10秒
            };
            esp_http_client_handle_t client = esp_http_client_init(&config);

            esp_http_client_set_method(client, HTTP_METHOD_POST);
            esp_http_client_set_header(client, "Content-Type", "audio/wav");
            esp_http_client_set_post_field(client, wav_data, wav_data_len);
            esp_err_t err = esp_http_client_perform(client);
            if (err == ESP_OK) {
                ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %"PRId64,
                        esp_http_client_get_status_code(client),
                        esp_http_client_get_content_length(client));
                // ESP_LOGI(TAG, "HTTP POST Response: %s", local_response_buffer);
            } else {
                ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
            }
            esp_http_client_cleanup(client);
            free(wav_data);
        }
        // 释放录音数据缓冲区
        free(recorded_data);
        recorded_data = NULL;
    }
}

bool i2s_recorder_recording(void) {
    return recording;
}

static void silence_detectiontask(void *arg) {
    // 静音阈值
    const int silence_threshold = NO_SOUND_THRESHOLD;
    // 静音计数器
    int silence_counter = 0;

    while (recording) {
        // 读取I2S数据
        size_t bytes_read;
        esp_err_t err = i2s_read(I2S_NUM, (void*)i2s_read_buff, I2S_BUF_SIZE, &bytes_read, portMAX_DELAY);
        if (err != ESP_OK) {
            ESP_LOGE(TAG, "I2S读取错误：%s", esp_err_to_name(err));
            continue;
        }

        // 计算音量
        int16_t max_volume = 0;
        for (size_t i = 0; i < bytes_read / 2; i++) {
            if (abs(((int16_t *)i2s_read_buff)[i]) > max_volume) {
                max_volume = abs(((int16_t *)i2s_read_buff)[i]);
            }
        }

        // 检查是否有声音
        if (max_volume < silence_threshold) {
            silence_counter++;
        } else {
            // 有声音，重置计数器
            silence_counter = 0;
        }

        // 如果连续 3 秒没有声音，执行特定任务
        if (silence_counter > (SILENCE_DURATION_MS / (I2S_BUF_SIZE * 1000 / SAMPLE_RATE))) {
            ESP_LOGI(TAG, "检测到 2 秒静音，执行特定任务...");
            // 停止录音
            i2s_recorder_stop();
            // 退出静音检测
            break;
        }

        // 延迟以减少CPU使用率
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }

    vTaskDelete(NULL);
}

/**
 * 录音任务
 */
void i2s_recorder_task(void *arg) {
    size_t bytes_read;
    // 静音阈值
    const int silence_threshold = NO_SOUND_THRESHOLD;
    // 静音计数器
    int silence_counter = 0;

    while (1) {
        if (button_pressed) {
            // 重置标志
            button_pressed = false; 
            if (recording) {
                i2s_recorder_stop();
            } else {
                led_manager_set_level(&record_led_manager, 1);
                i2s_recorder_start();
                xTaskCreate(silence_detectiontask, "SILENCE_DETECTIONTASK", 4096, NULL, 5, &silenceDetectionTaskHandle);
            }
        }

        if (recording) {
            // 送I2S读取数据
            esp_err_t err = i2s_read(I2S_NUM, (void *)i2s_read_buff, I2S_BUF_SIZE, &bytes_read, portMAX_DELAY);
            if (err != ESP_OK) {
                ESP_LOGE(TAG, "I2S读取错误：%s", esp_err_to_name(err));
            } else {
                // 更新总读取字节数
                if (total_bytes_read + bytes_read <= 1024 * 1024) {
                    memcpy(recorded_data + total_bytes_read, i2s_read_buff, bytes_read);
                    total_bytes_read += bytes_read;
                } else {
                    ESP_LOGW(TAG, "记录缓冲区溢出");
                    i2s_recorder_stop();
                }
                // 处理或存储数据（这里仅打印读取的字节数）
                ESP_LOGI(TAG, "正在录制… 读取 %d 个字节", bytes_read);
            }
        } else {
            // ESP_LOGI(TAG, "未在录音");
            // 延迟以减少CPU使用率
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
    }

    // 释放缓冲区
    free(i2s_read_buff);
}